package com.dream.base.web.interceptor;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.dream.app.service.UserService;
import com.dream.model.app.AppAbstractUser;
import com.dream.model.app.AppUser;
import com.dream.utils.annotation.SkipAuthority;
import com.dream.utils.cookie.CookieUtils;
import com.dream.utils.web.provider.AuthorityProvider;
import com.dream.vo.api.StatusCode;
import com.dream.vo.base.Constants;
import com.google.common.collect.Lists;


/**
 * @copyright evan
 * @author evan
 * @Revision
 * @date 2013/08/30
 */
public class AccessAuthorityInterceptor extends HandlerInterceptorAdapter {

	private AuthorityProvider authorityProvider;
	
	public void setAuthorityProvider(AuthorityProvider authorityProvider) {
		this.authorityProvider = authorityProvider;
	}
	
	private static final List<String> SKIP_SESSION = Lists.newArrayList();
	static{
		
		SKIP_SESSION.add("/app/login");
		SKIP_SESSION.add("/api/login");
	}

	@Autowired
	private UserService userService;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws ServletException, IOException {

		boolean proceed = true;

		if (handler instanceof HandlerMethod) {
			
			Method method = (Method) ((HandlerMethod) handler).getMethod();
			// validate the remember me function, then auto login by the remember me function 
			validateRememberMe(request);
			if(notLogin(request)){//not login
				handleNosesion(request, response, handler);
				proceed = false;
			}else if (!method.isAnnotationPresent(SkipAuthority.class)) {
				if (!authorityProvider.hasAuthority(request,null)) {//not authorize
					handleNotAuthorized(request, response, handler);
					proceed = false;
				}
			}
		}

		return proceed;
	}
	
	protected void handleNosesion(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws ServletException, IOException {
		
		if( request.getRequestURL().toString().contains("api")){
			response.setStatus(StatusCode.NOT_AUTHORIZE);
		}else{
			
			if (request.getHeader("x-requested-with") != null && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){  
				response.setStatus(911);//表示session timeout  
	        }else{
				String uri = request.getContextPath() + Constants.APP_LOGIN+"?timeout=true";
				response.sendRedirect(uri);
	        }
		}
	}
	
	protected void handleNotAuthorized(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws ServletException, IOException {
		if( request.getRequestURL().toString().contains("api")){
			response.setStatus(StatusCode.NOT_AUTHORIZE);
		}else{
			String uri = request.getContextPath() + Constants.APP_LOGIN;
			response.sendRedirect(uri);
		}
	}
	
	private boolean notLogin(HttpServletRequest request){
		boolean res = false;
		HttpSession session = request.getSession(false);
		if(session != null){
			
			AppAbstractUser user = (AppAbstractUser)session.getAttribute(Constants.USER_ID);
			if(user != null && StringUtils.isNotBlank(user.getId())){
				res = true;
			}
		}
		//only the  login controller need not validate
		if(!res){
			String uri = request.getRequestURL().toString();
			if( StringUtils.isNotBlank(uri)){
				for(String skip : SKIP_SESSION){
					if(uri.contains(skip)){
						res = true;
						break;
					}
				}
			}
		}
		return !res;
	}

	private void validateRememberMe(HttpServletRequest request){
		// logout not need
		String uri = request.getRequestURL().toString(); 
		HttpSession session = request.getSession(false);
		// 不存在登录用户
		if (session == null || session.getAttribute(Constants.USER_ID) == null) {
			if(StringUtils.isNotBlank(uri) && !uri.contains(Constants.APP_LOGOUT_URI) && !uri.contains(Constants.APP_LOGIN_URI)) {
				
				// 有访问且不是login和logout处理
				String userId =  CookieUtils.getCookieValueByName(request, Constants.USER_ID);
				if(StringUtils.isNotBlank(userId)) {
					// we can get the userId from  the cookie, validate the user is exist or not
					AppUser user = userService.getDetail(userId);
					if(user != null) {
						// the user id which saved on the cookie is existed, populate in the session
						session = request.getSession(true);
						session.setAttribute(Constants.USER_ID, user);
					}
				} 
			}
		}
			
	}
}
